/*
 * @Description:
 * @Version: 1.0
 * @Author: biao.hu
 * @Date: 2021-10-22 13:21:11
 * @LastEditors: biao.hu
 * @LastEditTime: 2021-10-28 20:23:12
 */
package List

import (
	"fmt"
)

type (
	OneWayList struct {
		H OneWayListHeader
	}
	OneWayListHeader struct {
		Length    int
		MaxLength int
		Next      *OneWayListNode
		End       *OneWayListNode
	}
	OneWayListNode struct {
		Value interface{}
		Next  *OneWayListNode
	}
)

/**
 * @description: 插入新节点
 * @param {interface{}} val
 * @return {error}
 */
func (o *OneWayList) InsertNode(val interface{}) error {
	// 链表长度超过限定，不允许再插入
	if o.H.MaxLength == o.H.Length {
		str := fmt.Sprintf("List length out of limit, maximum length is %d, and your length is %d.", o.H.MaxLength, o.H.Length+1)
		panic(str)
	}
	// 判断是否为第一节点
	if o.H.Next == nil && o.H.MaxLength > 0 {
		o.H.Next = &OneWayListNode{Value: val}
		o.H.Length++
		return nil
	}

	temp := o.H.Next
	for {
		if temp.Next == nil {
			temp.Next = &OneWayListNode{Value: val}
			o.H.Length++
			break
		}
		temp = temp.Next
	}
	return nil
}

/**
 * @description: 通过end节点直接插入--尾插法
 * @param {interface{}} val
 * @return {error}
 */
func (o *OneWayList) InsertNodeToEnd(val interface{}) error {
	// 链表长度超过限定，不允许再插入
	if o.H.MaxLength == o.H.Length {
		str := fmt.Sprintf("List length out of limit, maximum length is %d, and your length is %d.", o.H.MaxLength, o.H.Length+1)
		panic(str)
	}
	node := &OneWayListNode{Value: val, Next: nil}
	// 判断是否为第一节点
	if o.H.End == nil {
		o.H.Next = node
	} else {
		o.H.End.Next = node
	}

	o.H.End = node
	o.H.Length++

	return nil
}

/**
 * @description: 头插法
 * @param {int} val
 * @return {error}
 */
func (o *OneWayList) InsertNodeToHeader(val int) error {
	// 链表长度超过限定，不允许再插入
	if o.H.MaxLength == o.H.Length {
		str := fmt.Sprintf("List length out of limit, maximum length is %d, and your length is %d.", o.H.MaxLength, o.H.Length+1)
		panic(str)
	}

	node := &OneWayListNode{Value: val, Next: o.H.Next}
	o.H.Next = node
	if o.H.Length == 0 {
		o.H.End = o.H.Next
	}
	o.H.Length++

	return nil
}

/**
 * @description: 删除节点--根据值删除
 * @param {interface{}} val
 * @return {error}
 */
func (o *OneWayList) DeleteNodeByValue(val interface{}) error {
	o.Validator()
	fmt.Println("Delete the node whose value is ", val)
	// 判断是否为第一节点
	if o.H.Next.Value == val {
		o.H.Next = o.H.Next.Next
		o.H.Length--
		_ = o.DeleteNodeByValue(val)
	}
	p := o.H.Next
	// 保存删除前节点的上一节点
	parent := p
	for {
		if p.Value == val {
			parent.Next = p.Next
			o.H.Length--
		}
		parent = p
		p = p.Next
		if p == nil {
			break
		}
	}
	return nil
}

/**
 * @description: 删除节点--根据位置删除,下标从0开始
 * @param {int} index
 * @return {error}
 */
func (o *OneWayList) DeleteNodeByIndex(index int) error {
	o.Validator()
	if index < 0 || index > o.H.Length {
		panic("The location you want to delete is illegal！")
	}
	fmt.Println("Delete the node whose index is ", index)
	// 判断是否为第一个元素
	if index == 0 {
		o.H.Next = o.H.Next.Next
		o.H.Length--
	} else {
		count := 0
		p := o.H.Next
		// 保存删除前节点的上一节点
		parent := p
		for {
			// 如果删除的位置找到
			if count == index {
				parent.Next = p.Next
				o.H.Length--
				break
			}
			parent = p
			p = p.Next
			count++
		}
	}
	return nil
}

/**
 * @description: 验证列表
 * @param {*}
 * @return {*}
 */
func (o *OneWayList) Validator() {
	if o.H.Length == 0 {
		panic("The length of the list is 0")
	}
}

/**
 * @description: 展示链表数据
 * @param {*}
 * @return {*}
 */
func (o *OneWayList) Show() {
	// 判断链表是否为空
	o.Validator()
	str := fmt.Sprintf("Header: [len(%d), max(%d), index_start(%d), index_end(%d)]", o.H.Length, o.H.MaxLength, o.H.Next.Value, o.H.End.Value)
	fmt.Print(str)
	p := o.H.Next
	for {

		// 如果下一节点不存在，则退出
		if p == nil {
			break
		}
		fmt.Print("->")
		fmt.Print("Node:", p.Value)
		p = p.Next
	}
	fmt.Println()
}

/**
 * @description: 该方法放在main方法里面运行
 * @param {*}
 * @return {*}
 */
func RunDemo() {
	o := OneWayList{H: OneWayListHeader{Length: 0, Next: nil, MaxLength: 100, End: nil}}
	for i := 0; i < 10; i++ {
		// 遍历型尾插法
		// _ = o.InsertNode(i)
		// 通过尾指针尾插法
		// _ = o.InsertNodeToEnd(i)
		// 头插法
		_ = o.InsertNodeToHeader(i)
	}
	// 通过值删除节点元素
	//_ = o.DeleteNodeByValue(1)
	// 通过下标删除元素
	//_=o.DeleteNodeByIndex(1)
	o.Show()
}
